{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 可接受任意数量参数的函数:*\n",
    "def avf(first,*rest):\n",
    "    return (first+sum(rest))/(1+len(rest))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.5"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "avf(1,2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2.5"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "avf(1,2,3,4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 接受任意数量的关键字参数,使用**开头\n",
    "# args是一个包含所有被传入关键字参数字典"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "def printInfo(**args):\n",
    "    items=args.items()\n",
    "    values=args.values()\n",
    "    print(items)\n",
    "    print(\"关键字:\",args.keys())\n",
    "    print(\"内容:\",values)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "dict_items([('name', 'youxiangyang'), ('age', 12)])\n",
      "关键字: dict_keys(['name', 'age'])\n",
      "内容: dict_values(['youxiangyang', 12])\n"
     ]
    }
   ],
   "source": [
    "printInfo(name=\"youxiangyang\",age=12)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 希望某些函数参数需要强制使用关键字参数传递\n",
    "# 将强制关键词参数放到某个*参数或者单个*后面就可以实现"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "def recv(maxsize,*,block):\n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "recv() takes 1 positional argument but 2 were given",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-19-930377d52ca9>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mrecv\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1024\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m: recv() takes 1 positional argument but 2 were given"
     ]
    }
   ],
   "source": [
    "recv(1024,True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "recv(12,block=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "def mininum(*values,clip=None):\n",
    "    m=min(values)\n",
    "    if clip is not None:\n",
    "        m=clip if clip>m else m\n",
    "    return m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mininum(1,2,3,4,10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mininum(1,0,-12,2,clip=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "#很多情况下，使用强制关键字参数会比使用位置参数表意更加清晰，程序也更加具 有可读性。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "#  给函数参数增加元信息\n",
    "# python 解释器不会对这些注解添加任何的语义。它们不会被类型检查，运行时跟 没有加注解之前的效果也没有任何差距。\n",
    "# 然而，对于那些阅读源码的人来讲就很有帮助 啦。第三方工具和框架可能会对这些注解添加语义。同时它们也会出现在文档中。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "def add(x:int,y:int)->int:\n",
    "    return x+y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function add in module __main__:\n",
      "\n",
      "add(x: int, y: int) -> int\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(add)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 返回多个值的函数\n",
    "def myfunc1():\n",
    "    return 1,2,4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "a,b,c=myfunc1()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 2 4\n"
     ]
    }
   ],
   "source": [
    "print(a,b,c)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [],
   "source": [
    "#定义有默认参数的函数\n",
    "def myfunc(a,b=12):\n",
    "    print(a,b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 12\n"
     ]
    }
   ],
   "source": [
    "myfunc(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 3\n"
     ]
    }
   ],
   "source": [
    "myfunc(1,3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [],
   "source": [
    "def myfunc1(a,b=None):\n",
    "    if b is None:\n",
    "        print(a,b)\n",
    "    else:\n",
    "        print(a,\"??\",b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "12 ?? [1, 2, 3]\n"
     ]
    }
   ],
   "source": [
    "myfunc1(12,[1,2,3])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 匿名函数或内联函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [],
   "source": [
    "add=lambda x,y:x-y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "10"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "add(12,2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [],
   "source": [
    "mylist=[1.4,11.4,22,5,1,22,4]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 1.4, 4, 5, 11.4, 22, 22]"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sorted(mylist)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [],
   "source": [
    "lst1=['Ac s','Sem 1','Jh s','ll s']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['Ac s', 'Jh s', 'll s', 'Sem 1']"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sorted(lst1,key=lambda info:info.split(' ')[0].lower())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 匿名函数捕获变量值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [],
   "source": [
    "x=10"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [],
   "source": [
    "a=lambda y:x+y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [],
   "source": [
    "x=20"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [],
   "source": [
    "b=lambda y:x+y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "30"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "40"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b(20)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [],
   "source": [
    "# x是一个自由变量,在运行时绑定值,而不是定义时候就绑定.这个和普通的函数时不一样的.使用lambda表达式时候,x的值就是执行时候的值."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [],
   "source": [
    "func=[lambda x,n=n:x+n for n in range(5)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1\n",
      "2\n",
      "3\n",
      "4\n"
     ]
    }
   ],
   "source": [
    "for i in func:\n",
    "    print(i(0))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [],
   "source": [
    "#将单方法的类转换为函数\n",
    "# 你有一个除 __init__() 方法外只定义了一个方法的类。为了简化代码，你想将它 转换成一个函数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [],
   "source": [
    "from urllib.request import urlopen\n",
    "class UrlTemplate: \n",
    "    def __init__(self, template):\n",
    "        self.template = template\n",
    "    def open(self, **kwargs): \n",
    "        return urlopen(self.template.format_map(kwargs))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [],
   "source": [
    "def urltemplate(template):\n",
    "    def opener(**args):\n",
    "        return urlopen(template.format_map(args))\n",
    "    return opener"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "大部分情况下，你拥有一个单方法类的原因是需要存储某些额外的状态来给方法 使用。  \n",
    "比如，定义 UrlTemplate 类的唯一目的就是先在某个地方存储模板值，以便将来 可以在 open() 方法中使用。   \n",
    "使用一个内部函数或者闭包的方案通常会更优雅一些。简单来讲，一个闭包就是 一个函数，只不过在函数内部带上了一个额外的变量环境。  \n",
    "闭包关键特点就是它会记 住自己被定义时的环境。因此，在我们的解决方案中，opener() 函数记住了 template 参数的值，并在接下来的调用中使用它。  \n",
    "任何时候只要你碰到需要给某个函数增加额外的状态信息的问题，都可以考虑使 用闭包。  \n",
    "相比将你的函数转换成一个类而言，闭包通常是一种更加简洁和优雅的方案。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 带额外状态信息的回调函数\n",
    "#你的代码中需要依赖到回调函数的使用 (比如事件处理器、等待后台任务完成后的 回调等)，\n",
    "#并且你还需要让回调函数拥有额外的状态值，以便在它的内部使用到。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [],
   "source": [
    "def apply_async(func,args,*,callback):\n",
    "    result=func(*args)\n",
    "    callback(result)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {},
   "outputs": [],
   "source": [
    "def print_res(result):\n",
    "    print(\"Get:\",result)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [],
   "source": [
    "def add(x,y):\n",
    "    return x+y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Get: 5\n"
     ]
    }
   ],
   "source": [
    "apply_async(add,(2,3),callback=print_res)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {},
   "outputs": [],
   "source": [
    "#注意到 print_result() 函数仅仅只接受一个参数 result 。不能再传入其他信息。 \n",
    "#而当你想让回调函数访问其他变量或者特定环境的变量值的时候就会遇到麻烦。\n",
    "#为了让回调函数访问外部信息，一种方法是使用一个绑定方法来代替一个简单函 数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ResultHandler:\n",
    "    def __init__(self):\n",
    "        self.sequence=0\n",
    "    def handler(self,result):\n",
    "        self.sequence+=1\n",
    "        print('[{}] Get {}'.format(self.sequence,result))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {},
   "outputs": [],
   "source": [
    "r=ResultHandler()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1] Get 6\n"
     ]
    }
   ],
   "source": [
    "apply_async(add,(2,4),callback=r.handler)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2] Get nameage\n"
     ]
    }
   ],
   "source": [
    "apply_async(add,(\"name\",\"age\"),callback=r.handler)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 第二种方式，作为类的替代，可以使用一个闭包捕获状态值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [],
   "source": [
    "def make_hander():\n",
    "    sequence=1\n",
    "    def hander(result):\n",
    "        nonlocal sequence\n",
    "        sequence+=1\n",
    "        print(\"[{}] Got {}\".format(sequence,result))\n",
    "    return hander"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "metadata": {},
   "outputs": [],
   "source": [
    "handers=make_hander()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2] Got 2\n"
     ]
    }
   ],
   "source": [
    "apply_async(add,(1,1),callback=handers)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 还有另外一个更高级的方法，可以使用协程来完成同样的事情"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "metadata": {},
   "outputs": [],
   "source": [
    "def make_hander_new():\n",
    "    sid=1\n",
    "    while True:\n",
    "        result=yield\n",
    "        sid+=1\n",
    "        print(\"{} get {}\".format(sid,result))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "metadata": {},
   "outputs": [],
   "source": [
    "hand=make_hander_new()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "metadata": {},
   "outputs": [],
   "source": [
    "next(hand)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2 get 22\n"
     ]
    }
   ],
   "source": [
    "apply_async(add,(11,11),callback=hand.send)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "hide_input": false,
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
